﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;
using System;

namespace ME.Macros {

	public static class MacrosTemplates {

		//const string pattern = @"(\s?)#region\s+macros\s+([A-Za-z0-9]+)\s+(.*?)#endregion";

		const string pattern = @"(\s?)#region\s+macros\s+(?<macrosName>[A-Za-z0-9\.]+)\s+(?<macrosArgs>\(.*?\).*?\n|)(?<macrosBody>.*?)#endregion";

		const string macrosTemplate = @"#region macros {{NAME}}
/*
 * This code is auto-generated by Macros Module
 * Do not change anything
 */
{{CODE}}
#endregion";

		const string patternDefinition = @"#region\s+source\s+macros\s+([A-Za-z0-9\.]+)\s+(.*?)\s+#endregion";
		const string patternDefinitionName = @"#macros\s+([A-Za-z0-9\.]+)";

		public static bool ContainsMacros(this string text) {

			Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
			return rgx.IsMatch(text);

		}

		public static List<string> GetMacrosNames(this string text) {

			var names = new List<string>();

			Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
			var matches = rgx.Matches(text);

			foreach (Match match in matches) {

				names.Add(match.Groups[2].Value);

			}

			return names;

		}

		public static string GetPartOfMacros(string sourceText, string macrosName, string partName) {

			var res = string.Empty;

			Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
			var matches = rgx.Matches(sourceText);

			foreach (Match match in matches) {
				
				if (match.Groups["macrosName"].Value == macrosName) {
					res = match.Groups[partName].Value;
					break;
				}
				
			}

			return res;

		}

		public static string RefreshMacros(this string sourceText, string macrosName, string macrosCode) {

			var vars = MacrosTemplates.GetParameters(sourceText, macrosName);
			var rawArgs = MacrosTemplates.GetPartOfMacros(sourceText, macrosName, "macrosArgs");

			var macrosText = macrosTemplate.Replace("{{NAME}}", macrosName);
			macrosText = macrosText.Replace("{{CODE}}", macrosCode);

			Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
			var match = rgx.Match(sourceText);
			var spaces = match.Groups[1].Value;

			macrosText = macrosText.Replace(Environment.NewLine, Environment.NewLine + spaces);

			var pt = @"(\s?)#region\s+macros\s+" + macrosName + "\\s+(.*?)#endregion";

			rgx = new Regex(pt, RegexOptions.IgnoreCase | RegexOptions.Singleline);
			//if (UnityEngine.UI.Windows.Constants.LOGS_ENABLED == true) UnityEngine.Debug.Log(macrosName + ": " + sourceText + " => " + macrosText);
			sourceText = rgx.Replace(sourceText, spaces + macrosText);

			foreach (var item in vars) {
				
				sourceText = sourceText.Replace("/*{" + item.Key + "}*/", item.Value);
				sourceText = sourceText.Replace("{" + item.Key + "}", item.Value);

			}

			sourceText = sourceText.Replace(macrosName, macrosName + " " + rawArgs);

			return sourceText;

		}

		public static bool ContainsMacrosDefinition(this string text) {

			Regex rgx = new Regex(patternDefinition, RegexOptions.IgnoreCase | RegexOptions.Singleline);
			return rgx.IsMatch(text);

		}

		public static Dictionary<string, string> GetMacrosDefinitions(this string text) {

			Regex rgx = new Regex(patternDefinition, RegexOptions.IgnoreCase | RegexOptions.Singleline);
			var matches = rgx.Matches(text);

			var dic = new Dictionary<string, string>();
			foreach (Match match in matches) {

				if (dic.ContainsKey(match.Groups[1].Value) == false) {

					dic.Add(match.Groups[1].Value, match.Groups[2].Value);

				}

			}

			return dic;

		}

		private static Dictionary<string, string> GetParameters(string sourceText, string macrosName) {

			string args = MacrosTemplates.GetPartOfMacros(sourceText, macrosName, "macrosArgs").Replace("\r", string.Empty).Replace("\n", string.Empty).Trim();

			var res = new Dictionary<string, string>();

			if (string.IsNullOrEmpty(args) == false) {

				var separator = args.EndsWith(")") == true ? "," : args.Substring(args.Length - 1);
				args = args.Remove(args.IndexOf(")")).Replace("(", string.Empty);

				var pairs = args.Split(new string[] { separator }, System.StringSplitOptions.None);

				foreach (var pair in pairs) {

					var p = pair.Split(new string[] {":"}, System.StringSplitOptions.None);
					if (p.Length < 2) {

						if (UnityEngine.UI.Windows.Constants.LOGS_ENABLED == true) UnityEngine.Debug.LogWarning("Wrong args format");
						continue;

					}

					res.Add(p[0], p[1]);

				}

			}

			return res;

		}

	}



}